#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define COMMADN_SIZE 1024
#define COMMADN_MAX 128
#define Format "[%s@%s %s]# "

char *g_argv[COMMADN_MAX];
int g_argc = 0;


#define Env_Max 100
char* Env[Env_Max];
int g_Env = 0;

int lastpid = 0;

char test[1024];
char testenv[1024];

using namespace std;


void InitEnv()
{
    extern char** envrion;
    for(int i = 0;environ[i]; i++)
    {
        Env[i] = (char*)malloc(sizeof(environ[i]+1));
        strcpy(Env[i],environ[i]);
        g_Env++;
    }
    Env[g_Env++] =(char*)"test=ahh";
    Env[g_Env] = NULL;

    for(int i = 0; Env[i]; i++)
    {
        putenv(Env[i]);
    }
    environ = Env;
}


const char* GetUserName()
{
    char* name = getenv("USER");
    return name == NULL ? "" : name;
}

const char* GetHostName()
{
    char* name = getenv("HOSTNAME");
    return name == NULL ? "" : name;
}
const char* GetPwd()
{
    const char* name = getcwd(test,sizeof(test));
    if(name != NULL)
    {
        snprintf(testenv,sizeof(testenv),"PWD=%s",test);
        putenv(testenv);
    }
    return name == NULL ? "" : name;
}

const char* GetHome()
{
    char* name = getenv("HOME");
    return name == NULL ? "" : name;
} 

string DirName(const char* pwd)
{
#define slash "/"
    string tmp = pwd;
    if(tmp == slash)return slash;
    auto pos = tmp.rfind(slash);
    if(pos == string::npos) return "bug?";
    return tmp.substr(pos+1);
}

void CommandPrompt(char* promptline,int size)
{
    //snprintf(promptline,size,Format,GetUserName(),GetHostName(),GetPwd());
    snprintf(promptline,size,Format,GetUserName(),GetHostName(),DirName(GetPwd()).c_str());

}

//1.命令行提示符
void CommandLinePrompt()
{
    char promptline[COMMADN_SIZE];
    CommandPrompt(promptline,sizeof(promptline));
    printf("%s",promptline);
    fflush(stdin);
}

//2.读取用户输入命令
//"ls -l -a"
bool CommandLine(char* out, int size)
{
    char* n = fgets(out,size,stdin);
    if(n == NULL) return false;
    out[strlen(out)-1] = 0;
    return true;
}

//3.命令解释器 
//"ls -l -s" -> "ls" "-l" "-a"
void CommandTranslate(char* commandline)
{
#define seq " "
    g_argc = 0;
    g_argv[g_argc++] = strtok(commandline,seq);
    while((bool)(g_argv[g_argc++] = strtok(nullptr,seq)));
    g_argc--;
}

//4.判断是否为内建命令
//"cd" ".."

void Cd()
{
    //cd
    if(g_argc == 1)
    {
        string home = GetHome();
        chdir(home.c_str());   
    }else 
    {
        string tmp = g_argv[1];
        chdir(tmp.c_str());
    }
}

void Echo()
{
    // $?   $ENV  ""
    if(g_argc == 2)
    {
        string tmp = g_argv[1];
        if(tmp == "$?")
        {
            cout << lastpid << endl;
        }
        else if (tmp[0] == '$')
        {
            string s = tmp.substr(1);
            char* Env = getenv(s.c_str());
            cout << Env << endl;
        }
        else
        {
            cout << tmp.c_str() << endl;
        }
    }
}

bool CheckAndBuiltin()
{
    string tmp = g_argv[0];
    if(tmp == "cd")
    {
        Cd();
        return true;
    }
    else if (tmp == "echo")
    {
        Echo();
        return true;
    }
    else
    {
        return false;
    }
}

//4.执行
void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        execvp(g_argv[0],g_argv);        
    }
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid > 0)
    {
        lastpid = WEXITSTATUS(status);
    }
}

int main()
{
    InitEnv();

    while(true)
    {
        //1.命令行提示符
        CommandLinePrompt();
        //2.读取用户输入命令
        char commandline[COMMADN_MAX];
        if(!CommandLine(commandline,sizeof(commandline))) continue;
        //3.命令解释
        CommandTranslate(commandline);
        //4.判断是否为内建命令
        if(CheckAndBuiltin())
            continue;
        //5.Execute
        Execute();
    }
    return 0;
}
